﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Web;

namespace Interfleet.SE.UICompiler.Core.ClosureCompilerREST
{
    /// <summary>
    /// ResultBuilder for Closure Compiler compiling via the RESTful API.
    /// </summary>
    public class CCRESTResultBuilder : ResultBuilder
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="arguments"><see cref="Arguments"/> used in compilation</param>
        public CCRESTResultBuilder(Arguments arguments)
            : this(arguments, new FileProvider())
        { }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="arguments"><see cref="Arguments"/> used in compilation</param>
        /// <param name="fileProvider">An <see cref="IFileProvider"/></param>
        public CCRESTResultBuilder(Arguments arguments, IFileProvider fileProvider)
            : base(arguments, fileProvider)
        { }

        /// <summary>
        /// Calls the agent and fetches error info
        /// </summary>
        /// <param name="result"></param>
        private void SetErrorInfo(CompileResult result)
        {
            var argsBuilder = new CCRESTArgumentBuilder(Arguments, "errors");
            var response = CCRESTCaller.Call(argsBuilder.Build());
            var rootElement = XElement.Parse(response);
            var errorElements = rootElement.Descendants("error").Where(d => d.Parent.Name == "errors");
            var sb = new StringBuilder();
            foreach (var errorElement in errorElements)
            {
                sb.Append("Error type=" + errorElement.Attribute("type").Value);
                sb.AppendLine();
                sb.Append("line: " + errorElement.Attribute("lineno").Value);
                sb.AppendLine();
                sb.AppendLine(errorElement.Attribute("line").Value);
                sb.AppendLine();
            }
            errorElements = rootElement.Descendants("error").Where(d => d.Parent.Name == "serverErrors");
            foreach (var errorElement in errorElements)
            {
                sb.Append("Error code=" + errorElement.Attribute("code").Value);
                sb.Append(" ");
                sb.AppendLine("description=" + errorElement.Value);
                sb.AppendLine();
            }
            result.StatusMessage = sb.ToString();
        }

        /// <summary>
        /// Builds up a <see cref="CompileResult"/> out of the <paramref name="statusMessage"/> delivered
        /// from the Google Closure Compiler REST API.
        /// </summary>
        /// <param name="statusMessage">The result returned by Google Closure Compiler REST API, normally the minified/compressed JavaScript</param>
        /// <param name="compilationStartedAt">Timestamp representing compilation start time.</param>
        /// <returns>A <see cref="CompileResult"/></returns>
        public override CompileResult Build(string statusMessage, DateTime compilationStartedAt)
        {
            var result = new CompileResult(Arguments.Files, Arguments.CompiledFileName);
            var rootElement = XElement.Parse(statusMessage);
            var codeElement = rootElement.Descendants("compiledCode").FirstOrDefault();
            if (codeElement != null && !string.IsNullOrEmpty(codeElement.Value))
            {
                FileInfoProvider.SaveToFile(Arguments.CompiledFileName, System.Uri.UnescapeDataString(codeElement.Value));
                result.Success = true;
                result.StatusMessage = string.Format("Compiled file: {0}", Arguments.CompiledFileName);
            }
            else
            {
                result.Success = false;
                SetErrorInfo(result);
            }
            return result;
        }
    }
}
